package com.example.demo.Aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.auth0.jwt.JWT;
import com.auth0.jwt.impl.PublicClaims;

import com.example.demo.Entity.User;
import com.example.demo.GeneralResponse.APIResponse;
import com.example.demo.Repository.IUserRepository;
import com.example.demo.Service.TokenService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.util.Date;

/**
 * @version: V0.3
 * @author: 郑皓杰 吴嘉鑫
 * @className: VerifyAspect
 * @packageName: com.example.demo.Aspect
 * @description: 这是AOP切面类
 * @data: 2021-07-14
 **/
@Component
@Aspect
@Order(0)
public class VerifyAspect {
	@Autowired
	private IUserRepository userRepository;
	@Autowired
	private TokenService tokenService;
	
	@Pointcut("@annotation(com.example.demo.Aspect.ValidatedSending)")
	public void check() {
	}
	
	@Pointcut("execution(public * com.example.demo.Controller.LoginController.*(..))")
	public void record() {	
	}
	
	@Pointcut("execution(public * com.example.demo.Controller.ManageController.*(..))")
	public void cutManageController() {
	}
	
	@Pointcut("execution(public * com.example.demo.Controller.ModifyController.*(..))")
	public void cutModifyController() {
	}
	
	@Pointcut("execution(public * com.example.demo.Controller.QueryController.*(..))")
	public void cutQueryController() {
	}
	
	@Pointcut("cutManageController()||cutModifyController()||cutQueryController()")
	public void generalCut() {
	}
	

	
	/**
	* @author:  郑皓杰 吴嘉鑫
	* @methodsName: doAroundRecord
	* @description: 在进行登录之前验证token
	* @param:  ProceedingJoinPoint proceedingjoinpoint
	* @return: Object
	* @throws: 
	*/
	@Around("record()")
	public Object doAroundRecord(ProceedingJoinPoint proceedingjoinpoint) throws Throwable{
		Object[] args = proceedingjoinpoint.getArgs();
		HttpServletRequest request = (HttpServletRequest) args[0];
		HttpServletResponse response = (HttpServletResponse) args[1];
		String nowtoken = request.getHeader("Token");
		response.setHeader("Access-Control-Expose-Headers","State,Token");
		if(nowtoken == null) {
			response.setHeader("State","FRISTPASS");
			APIResponse<?> o=(APIResponse<?>)proceedingjoinpoint.proceed(args);
			String result = o.getMessage();
			if(result.equals("successlogin")) { 
				response.setHeader("Token",tokenService.getToken(request.getParameter("username"), request.getParameter("password")));
				return o;
			}
			else
				return proceedingjoinpoint.proceed(args);//查不到token说明第一次登录，继续执行proceedingjoinpoint.proceed(args)
		}
		else {
			String username = JWT.decode(nowtoken).getClaim("username").asString();
			String password = JWT.decode(nowtoken).getClaim("password").asString();
			User user = userRepository.findByUsername(username) ;
			if(user == null||!user.getPassword().equals(password)) {
				response.setHeader("State","INVALIDTOKEN");
			//	response.sendRedirect("http://acfun.cn/");
				return APIResponse.fail("Invalid Token");
			}
			else {
				response.setHeader("State","REPEATEDPASS");
				return proceedingjoinpoint.proceed(args);
			}
		}
	}
	
	/**
	* @author:  郑皓杰 吴嘉鑫
	* @methodsName: doAroundOperation
	* @description: 在进行操作之前验证token
	* @param:  ProceedingJoinPoint proceedingjoinpoint
	* @return: Object
	* @throws: 
	*/
	@Around("generalCut()||check()")
	public Object doAroundOperation(ProceedingJoinPoint proceedingjoinpoint) throws Throwable{
		Object[] args = proceedingjoinpoint.getArgs();
		HttpServletRequest request = (HttpServletRequest) args[0];
		HttpServletResponse response = (HttpServletResponse) args[1];
		String nowtoken = request.getHeader("Token");
		response.setHeader("Access-Control-Expose-Headers","State,Token");
		if(nowtoken == null) {
			response.setHeader("State","UNAUTHORIZEDACCESS");
			return APIResponse.fail("Invalid Token");//查不到token说明还没登录
		}		
		Date date=JWT.decode(nowtoken).getClaim(PublicClaims.EXPIRES_AT).asDate();
		Date nowdate=new Date();
		if(date.before(nowdate))	return APIResponse.fail("Invalid Token");//token过期
		String username = JWT.decode(nowtoken).getClaim("username").asString();
		String password = JWT.decode(nowtoken).getClaim("password").asString();;
		User user = userRepository.findByUsername(username) ;
		String spassword = user.getPassword();
		if(user == null||!spassword.equals(password)) {
			response.setHeader("State","INVALIDTOKEN");
			return APIResponse.fail("Invalid Token");
		}
		response.setHeader("State","ALLOWED");
		response.setHeader("Token",tokenService.getToken(username, spassword));
		return proceedingjoinpoint.proceed(args);	
	}
}
